// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

const {ccclass, property} = cc._decorator;

@ccclass
export default class PuzzleLogic extends cc.Component {
    @property({type: cc.Texture2D})
    private texture: cc.Texture2D = null

    @property({type: cc.Texture2D})
    private maskTexture: cc.Texture2D = null

    @property({type: cc.Texture2D})
    private selectTexture: cc.Texture2D = null

    @property(cc.Sprite)
    private view:cc.Sprite = null

    private textureRect:cc.Rect
    private pieceTextureRect:cc.Rect
    private pieceRect:cc.Rect
    private viewRect:cc.Rect
    private beginPosition:cc.Vec2
    private pieces:cc.Node[] = []
    private masks:cc.Node[] = []
    private piecesNode:cc.Node
    private masksNode:cc.Node
    private effectsNode:cc.Node
    private selectEffect:cc.Node
    private selectBeforeTarget:cc.Node

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {}

    start () {
        this.createPuzzlePlane(3,3)
    }

    // update (dt) {}

    // 创建拼图面板
    private createPuzzlePlane(col:number, row:number) {
        console.log("create puzzle plane.")

        this.textureRect        = cc.rect(0, 0, this.texture.width, this.texture.height)
        this.pieceTextureRect   = cc.rect(0, 0, this.texture.width/col, this.texture.height/row)
        this.viewRect           = cc.rect(0, 0, this.view.node.width, this.view.node.height)
        this.pieceRect          = cc.rect(0, 0, this.view.node.width / col, this.view.node.height / row)
        this.beginPosition      = cc.v2(-this.viewRect.width/2 + this.pieceRect.width/2, this.viewRect.height/2 - this.pieceRect.height/2)
        
        console.log("textureRect:", this.textureRect)
        console.log("viewRect",     this.viewRect)
        console.log("pieceRect",    this.pieceRect)

        this.view.node.removeAllChildren()

        this.piecesNode = new cc.Node("pieces")
        this.view.node.addChild(this.piecesNode)

        this.masksNode = new cc.Node("masks")
        this.view.node.addChild(this.masksNode)

        this.effectsNode = new cc.Node("effects")
        this.view.node.addChild(this.effectsNode)

        for (let x = 0; x < col; x++) {
            for (let y = 0; y < row; y++) {
                this.createPuzzlePiece(x, y)
                this.createMaskLayer(x, y)
            }            
        }

        this.piecesNode.children.forEach(element => {
            this.pieces.push(element)
        })

        this.masksNode.children.forEach(element => {
            this.masks.push(element)
        })

        this.randomPuzzlePieces()
        //console.log(this.view)
    }

    // 创建拼图碎片
    private createPuzzlePiece(col:number, row:number) {
        console.log("create puzzle piece ", col, row)

        let node            = new cc.Node()
        let sprite          = node.addComponent(cc.Sprite)
        this.piecesNode.addChild(node)

        let newPieceRect    = cc.rect(col * this.pieceRect.width, row * this.pieceTextureRect.height, this.pieceTextureRect.width, this.pieceTextureRect.height)
        sprite.spriteFrame  = new cc.SpriteFrame(this.texture, newPieceRect)
        sprite.node.name    = "piece_" + col.toString() + row.toString()
        sprite.node.width   = this.pieceRect.width
        sprite.node.height  = this.pieceRect.height

        let x = this.beginPosition.x + (col * this.pieceRect.width)
        let y = this.beginPosition.y - (row * this.pieceRect.height)

        sprite.node.setPosition(x, y)
        sprite.node.on(cc.Node.EventType.TOUCH_END, this.onMouseUp, this)
    }

    // 创建遮罩层
    private createMaskLayer(col:number, row:number) {
        console.log("create mask layer ", col, row)

        let node        = new cc.Node()
        let sprite      = node.addComponent(cc.Sprite)
        this.masksNode.addChild(node)

        sprite.spriteFrame  = new cc.SpriteFrame(this.maskTexture) 
        sprite.node.name    = "mask_" + col.toString() + row.toString()
        sprite.node.width   = this.pieceRect.width
        sprite.node.height  = this.pieceRect.height

        let x = this.beginPosition.x + (col * this.pieceRect.width)
        let y = this.beginPosition.y - (row * this.pieceRect.height)

        sprite.node.setPosition(x, y)
    }

    // 创建选中标志
    private createSelectEffect() {
        console.log("create select effect")

        let node        = new cc.Node()
        let sprite      = node.addComponent(cc.Sprite)
        this.effectsNode.addChild(node)

        sprite.spriteFrame = new cc.SpriteFrame(this.selectTexture)
        sprite.node.name    = "select"
        sprite.node.width   = this.pieceRect.width
        sprite.node.height  = this.pieceRect.height

        this.selectEffect = node
    }    

    // 随机打乱拼图碎片
    private randomPuzzlePieces() {
        console.log("randon puzzle pieces")

        for (let index = 0; index < this.masks.length/2; index++) {
            let indexA = this.randomInt(0, this.masks.length)
            let indexB = this.randomInt(0, this.masks.length)
            this.swapPuzzlePieces(indexA, indexB)
        }
    }

    // 交换拼图块
    private swapPuzzlePieces(indexA:number, indexB:number) {
        console.log("swap puzzle pieces ", indexA, "=>", indexB)

        let swapA = this.pieces[indexA]
        let swapB = this.pieces[indexB]
        let swapPositionA = this.pieces[indexA].getPosition()
        let swapPositionB = this.pieces[indexB].getPosition()

        swapA.setPosition(swapPositionB)
        swapB.setPosition(swapPositionA)
    }

    // 点击拼图块
    private onMouseUp(event:cc.Event.EventMouse) {
        //console.log(event.currentTarget)
        let swapA = event.currentTarget
        let swapB = this.selectBeforeTarget

        if (this.selectEffect == null) {
            this.createSelectEffect()
        }

        this.selectEffect.opacity = 255
        this.selectEffect.setPosition(swapA.getPosition())

        if (swapB != null) {
            let swapPositionA = swapA.getPosition()
            let swapPositionB = swapB.getPosition()

            swapA.setPosition(swapPositionB)
            swapB.setPosition(swapPositionA)
            this.selectBeforeTarget = null
            this.selectEffect.opacity = 0

            this.checkSuccess()
        } else {
            this.selectBeforeTarget = event.currentTarget
        }  
    }

    // 检测是否完成拼图
    private checkSuccess() {
        let success = true
        for (let index = 0; index < this.masks.length; index++) {
            if (this.masks[index].x != this.pieces[index].x || this.masks[index].y != this.pieces[index].y) {
                console.log("fail")
                success = false
                continue
            }
        }

        if (success) {
            console.log("success")
        }
    }

    // 随机数
    private randomInt(min:number, max:number) {
        return Math.floor(Math.random() * 100000) % max + min;
    }
}
